package com.heu.blood.bloodtest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heu.blood.bloodtest.dao.BloodTestDao;
import com.heu.blood.bloodtest.entity.BloodTestEntity;
import com.heu.blood.bloodtest.entity.PreTestResult;
import com.heu.blood.bloodtest.entity.TestResult;
import com.heu.blood.bloodtest.service.BloodSamplePatientService;
import com.heu.blood.bloodtest.service.BloodSampleService;
import com.heu.blood.bloodtest.service.BloodTestService;
import com.heu.blood.bloodtest.vo.BloodSamplePatientReportVo;
import com.heu.blood.bloodtest.vo.BloodSamplePatientTestVo;
import com.heu.blood.bloodtest.vo.BloodSampleReportVo;
import com.heu.blood.bloodtest.vo.BloodSampleTestVo;
import com.heu.blood.common.commponent.DictionaryLoader;
import com.heu.blood.common.enums.DictDataEnum;
import com.heu.blood.common.utils.PageUtils;
import com.heu.blood.common.utils.Query;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@Service("bloodTestService")
public class BloodTestServiceImpl extends ServiceImpl<BloodTestDao, BloodTestEntity> implements BloodTestService {


    @Autowired
    private BloodTestDao bloodTestDao;

    @Autowired
    private DictionaryLoader dictionaryLoader;

    @Autowired
    private BloodSamplePatientService bloodSamplePatientService;

    @Autowired
    private BloodSampleService bloodSampleService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        // 创建BloodTestEntity对象接收查询条件
        BloodTestEntity bloodTestEntity = new BloodTestEntity();
        // 接收条件
        if (Strings.isNotBlank((String) params.get("bloodTestId"))){
            bloodTestEntity.setBloodTestId((String) params.get("bloodTestId")); // 血液检测表id
        }
        if (Strings.isNotBlank((String) params.get("bloodSampleId"))){
            bloodTestEntity.setBloodSampleId((String) params.get("bloodSampleId")); // 样本表id
        }
        // 创建queryWrapper
        LambdaQueryWrapper<BloodTestEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件
        queryWrapper.eq(Strings.isNotBlank(bloodTestEntity.getBloodTestId()), BloodTestEntity::getBloodTestId, bloodTestEntity.getBloodTestId())
                    .eq(Strings.isNotBlank(bloodTestEntity.getBloodSampleId()), BloodTestEntity::getBloodSampleId, bloodTestEntity.getBloodSampleId())
                    .eq(BloodTestEntity::getIfShow, 1);

        IPage<BloodTestEntity> page = this.page(
                new Query<BloodTestEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    /**
     * 分页联表条件查询病人血液样本和检测结果
     * @param params
     * @return
     */
    @Override
    public PageUtils selectSamplePatientTestPage(Map<String, Object> params) {
        // 创建BloodSamplePatientTestVo对象接收条件
        BloodSamplePatientTestVo bloodSamplePatientTestVo = new BloodSamplePatientTestVo();
        if (Strings.isNotBlank((String) params.get("bloodTestId"))) {
            bloodSamplePatientTestVo.setBloodTestId((String) params.get("bloodTestId")); // 检测单号
        }
        if (Strings.isNotBlank((String) params.get("bloodSampleId"))){
            bloodSamplePatientTestVo.setBloodSampleId((String) params.get("bloodSampleId")); // 样本单号
        }
        if (Strings.isNotBlank((String) params.get("inspector"))){
            bloodSamplePatientTestVo.setInspector((String) params.get("inspector")); // 检测人
        }
        if (Strings.isNotBlank((String) params.get("patientId"))){
            bloodSamplePatientTestVo.setPatientId((String) params.get("patientId")); // 患者id （也是，谁会用患者id来查啊）
        }
        if (Strings.isNotBlank((String) params.get("patientName"))){
            bloodSamplePatientTestVo.setPatientName((String) params.get("patientName")); // 患者姓名
        }
        if (Strings.isNotBlank((String) params.get("collector"))){
            bloodSamplePatientTestVo.setCollector((String) params.get("collector")); // 采血者
        }
        if (Strings.isNotBlank((String) params.get("recipient"))){
            bloodSamplePatientTestVo.setRecipient((String) params.get("recipient")); // 接收者
        }
        if (Strings.isNotBlank((String) params.get("reason"))){
            bloodSamplePatientTestVo.setReason((String) params.get("reason")); // (退样本后给出相应原因)
        }
        if (Strings.isNotBlank((String) params.get("department"))){
            bloodSamplePatientTestVo.setDepartment((String) params.get("department")); // 申请科室
        }
        if (Strings.isNotBlank((String) params.get("applicationProjects"))){
            bloodSamplePatientTestVo.setApplicationProjects((String) params.get("applicationProjects")); // 申请项目
        }
        if (Strings.isNotBlank((String) params.get("inspectStatus"))){
            bloodSamplePatientTestVo.setInspectStatus((String) params.get("inspectStatus"));
        }


        // 接收时间范围条件
        String inspectStartTime = null; // 检测时间左边界
        String inspectEndTime = null; // 检测时间有边界
        String receivedStartTime = null; // 接收时间左边界
        String receivedEndTime = null; // 接收时间右边界
        String collectStartTime = null; // 采血时间左边界
        String collectEndTime = null; // 采血时间右边界

        if (Strings.isNotBlank((String) params.get("inspectStartTime"))){
            inspectStartTime = (String) params.get("inspectStartTime");
        }
        if (Strings.isNotBlank((String) params.get("inspectEndTime"))){
            inspectEndTime = (String) params.get("inspectEndTime");
        }
        if (Strings.isNotBlank((String) params.get("receivedStartTime"))){
            receivedStartTime = (String) params.get("receivedStartTime");
        }
        if (Strings.isNotBlank((String) params.get("receivedEndTime"))){
            receivedEndTime = (String) params.get("receivedEndTime");
        }
        if (Strings.isNotBlank((String) params.get("collectStartTime"))){
            collectStartTime = (String) params.get("collectStartTime");
        }
        if (Strings.isNotBlank((String) params.get("collectEndTime"))){
            collectEndTime = (String) params.get("collectEndTime");
        }

        // 构建querywrapper
        QueryWrapper<BloodSamplePatientTestVo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Strings.isNotBlank(bloodSamplePatientTestVo.getBloodTestId()), "bt.blood_test_id", bloodSamplePatientTestVo.getBloodTestId())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getBloodSampleId()), "bt.blood_sample_id", bloodSamplePatientTestVo.getBloodSampleId())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getInspector()), "bt.inspector", bloodSamplePatientTestVo.getInspector())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getPatientId()), "bsp.patient_id", bloodSamplePatientTestVo.getPatientId())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getPlace()), "bsp.place", bloodSamplePatientTestVo.getPlace())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getRecipient()), "bsp.recipient", bloodSamplePatientTestVo.getRecipient())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getReason()), "bsp.reason", bloodSamplePatientTestVo.getReason())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getDepartment()), "bsp.department", bloodSamplePatientTestVo.getDepartment())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getApplicationProjects()), "bt.application_projects", bloodSamplePatientTestVo.getApplicationProjects())
                .eq(Strings.isNotBlank(bloodSamplePatientTestVo.getInspectStatus()), "bt.inspect_status", bloodSamplePatientTestVo.getInspectStatus())
                .ge(Strings.isNotBlank(inspectStartTime), "bt.inspect_time", inspectStartTime)
                .le(Strings.isNotBlank(inspectEndTime), "bt.inspect_time", inspectEndTime)
                .ge(Strings.isNotBlank(collectStartTime), "bsp.collect_time", collectStartTime)
                .le(Strings.isNotBlank(collectEndTime), "bsp.collect_time", collectEndTime)
                .ge(Strings.isNotBlank(receivedStartTime), "bsp.received_time", receivedStartTime)
                .le(Strings.isNotBlank(receivedEndTime), "bsp.received_time", receivedEndTime);

        // IPage分页查询
        IPage<BloodSamplePatientTestVo> page = bloodTestDao.selectSamplePatientTestPage(
                new Query<BloodSamplePatientTestVo>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    /**
     * 将检测项目和检测结果单独列出来
     * @param bloodSampleId
     * @return
     */
    @Override
    public Map<BloodSamplePatientReportVo, List<TestResult>> queryPatientTestResult(String bloodSampleId) {
        // 1、通过bloodSampleId找到样本表信息
        BloodSamplePatientReportVo bloodSamplePatientReportVo = bloodSamplePatientService.selectSamplePatientReport(bloodSampleId);

        if (bloodSamplePatientReportVo == null){
            return null;
        }
        // 2、通过bloodSampleId查询检测表信息
        List<BloodTestEntity> bloodTestEntityList = this.getBySampleId(bloodSampleId);
        if (bloodTestEntityList == null){
            return null;
        }
        // 3、设定一个List来存放查询出来的检测项目和检测结果<检测项目，<检测项目价格，检测结果>>
        List<TestResult> testResults = new ArrayList<>();

        Map<String, Map<String, String[]>> dict = dictionaryLoader.getDict();
        // 4、查询出相关检测
        for(BloodTestEntity bloodTest:bloodTestEntityList){
            //创建TestResult类用于存放检测结果
            TestResult testResult = new TestResult();
            //写入检测项目,检测结果,检测次数,价格
            testResult.setProjectName(dict.get(DictDataEnum.PAYMENT_PROJECT.code()).get(bloodTest.getApplicationProjects())[0]);
            testResult.setResult(bloodTest.getProjectResult());
            testResult.setCount(bloodTest.getCount());
            testResult.setPrice(bloodTest.getPrice());
            //将检测结果保存
            testResults.add(testResult);
        }
        // 5、再将相关检测与病人信息封装成一个新的对象返回
        Map<BloodSamplePatientReportVo, List<TestResult>> report = new HashMap<>();
        report.put(bloodSamplePatientReportVo, testResults);
        return report;
    }

    /**
     * 根据检测单号查询检测信息
     * @param bloodTestId
     * @return
     */
    @Override
    public List<BloodTestEntity> getByTestId(String bloodTestId) {
        // 构建lambdaQueryWrapper
        LambdaQueryWrapper<BloodTestEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Strings.isNotBlank(bloodTestId), BloodTestEntity::getBloodTestId, bloodTestId)
                    .eq(BloodTestEntity::getIfShow, 1);
        return bloodTestDao.selectList(queryWrapper);
    }

    /**
     * 根据样本单号查询检测信息
     * @param bloodSampleId
     * @return
     */
    @Override
    public List<BloodTestEntity> getBySampleId(String bloodSampleId) {
        // 构建lambdaQueryWrapper
        LambdaQueryWrapper<BloodTestEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Strings.isNotBlank(bloodSampleId), BloodTestEntity::getBloodSampleId, bloodSampleId)
                .eq(BloodTestEntity::getIfShow, 1);
        return bloodTestDao.selectList(queryWrapper);
    }

    /**
     * 查询血液样本检测报告
     * @param bloodSampleId
     * @return
     */
    @Override
    public Map<BloodSampleReportVo, List<TestResult>> queryTestResult(String bloodSampleId) {
        // 1、通过bloodSampleId找到样本表信息
        BloodSampleReportVo bloodSampleReportVo = bloodSampleService.selectSampleReport(bloodSampleId);
        if (bloodSampleReportVo == null){
            return null;
        }
        // 2、通过bloodSampleId查询检测表信息
        List<BloodTestEntity> bloodTestEntityList = this.getBySampleId(bloodSampleId);
        if (bloodTestEntityList == null){
            return null;
        }
        // 3、设定一个List来存放查询出来的检测项目和检测结果<检测项目,<检测项目价格，检测结果>>
        List<TestResult> testResults = new ArrayList<>();

        Map<String, Map<String, String[]>> dict = dictionaryLoader.getDict();
        // 4、查询出相关检测
        for(BloodTestEntity bloodTest:bloodTestEntityList){
            //创建TestResult类用于存放检测结果
            TestResult testResult = new TestResult();
            //写入检测项,检测结果,检测次数,检测价格
            testResult.setProjectName(dict.get(DictDataEnum.PAYMENT_PROJECT.code()).get(bloodTest.getApplicationProjects())[0]);
            testResult.setResult(bloodTest.getProjectResult());
            testResult.setCount(bloodTest.getCount());
            testResult.setPrice(bloodTest.getPrice());
            //将检测结果保存
            testResults.add(testResult);
        }
        // 5、再将相关检测与病人信息封装成一个新的对象返回
        Map<BloodSampleReportVo, List<TestResult>> report = new HashMap<>();
        report.put(bloodSampleReportVo, testResults);
        return report;
    }

    /**
     * 获取当天检验数量
     * @return
     */
    @Override
    public Integer getTestNum() {
        // 获取当天的起始时间和结束时间
        LocalDateTime startOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);

        // 创建lambdaQueryWrapper
        LambdaQueryWrapper<BloodTestEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加查询条件，使用日期范围查询
        queryWrapper.between(BloodTestEntity::getGmtCreate, startOfDay, endOfDay);

        // 使用count函数获取结果数量
        return bloodTestDao.selectCount(queryWrapper);
    }

    /**
     * 查询病人输血前检查结果
     * @param bloodSampleId
     * @return
     */
    @Override
    public List<PreTestResult> queryPatientPreTestResult(String bloodSampleId) {
        // 1、通过bloodSampleId查询检测表信息
        List<BloodTestEntity> bloodTestEntityList = this.getBySampleId(bloodSampleId);
        if (bloodTestEntityList == null){
            return null;
        }
        // 2、设定一个List来存放查询出来的检测项目和检测结果<检测项目,<检测项目价格，检测结果>>
        List<PreTestResult> preTestResults = new ArrayList<>();

        Map<String, Map<String, String[]>> dict = dictionaryLoader.getDict();
        // 3、查询出相关检测
        for(BloodTestEntity bloodTest:bloodTestEntityList){
            //创建TestResult类用于存放检测结果
            PreTestResult preTestResult = new PreTestResult();
            //写入检测项,检测结果,检测次数,检测价格
            preTestResult.setTestName(dict.get(DictDataEnum.PAYMENT_PROJECT.code()).get(bloodTest.getApplicationProjects())[0]);
            preTestResult.setResult(bloodTest.getProjectResult());
            //将检测结果保存
            preTestResults.add(preTestResult);
        }
        // 4、返回结果
        return preTestResults;
    }

    /**
     * 分页联表条件查询血液样本和检测结果
     * @param params
     * @return
     */
    @Override
    public PageUtils selectSampleTestPage(Map<String, Object> params) {
        // 用BloodSampleTestVo来封装查询条件
        BloodSampleTestVo bloodSampleTestVo = new BloodSampleTestVo();
        if (Strings.isNotBlank((String) params.get("bloodTestId"))) {
            bloodSampleTestVo.setBloodTestId((String) params.get("bloodTestId")); // 检测单号
        }
        if (Strings.isNotBlank((String) params.get("bloodSampleId"))){
            bloodSampleTestVo.setBloodSampleId((String) params.get("bloodSampleId")); // 样本单号
        }
        if (Strings.isNotBlank((String) params.get("inspector"))){
            bloodSampleTestVo.setInspector((String) params.get("inspector")); // 检测人
        }
        if (Strings.isNotBlank((String) params.get("bloodId"))){
            bloodSampleTestVo.setBloodId((String) params.get("bloodId")); // 血液id
        }
        if (Strings.isNotBlank((String) params.get("place"))){
            bloodSampleTestVo.setPlace((String) params.get("place")); // 血液样本存放位置
        }
        if (Strings.isNotBlank((String) params.get("recipient"))){
            bloodSampleTestVo.setRecipient((String) params.get("recipient")); // 签收人
        }
        if (Strings.isNotBlank((String) params.get("sampleStatus"))){
            bloodSampleTestVo.setSampleStatus((String) params.get("sampleStatus")); // 血液样本状态
        }
        if (Strings.isNotBlank((String) params.get("reason"))){
            bloodSampleTestVo.setReason((String) params.get("reason")); // 退回或者遗弃血液样本原因
        }
        if (Strings.isNotBlank((String) params.get("department"))){
            bloodSampleTestVo.setDepartment((String) params.get("department")); // 申请科室
        }
        if (Strings.isNotBlank((String) params.get("applicationProjects"))){
            bloodSampleTestVo.setApplicationProjects((String) params.get("applicationProjects")); // 申请项目
        }
        if (Strings.isNotBlank((String) params.get("inspectStatus"))){
            bloodSampleTestVo.setInspectStatus((String) params.get("inspectStatus"));
        }


        // 接收时间范围条件
        String inspectStartTime = null; // 检测时间左边界
        String inspectEndTime = null; // 检测时间有边界
        String receivedStartTime = null; // 接收时间左边界
        String receivedEndTime = null; // 接收时间右边界


        if (Strings.isNotBlank((String) params.get("inspectStartTime"))){
            inspectStartTime = (String) params.get("inspectStartTime");
        }
        if (Strings.isNotBlank((String) params.get("inspectEndTime"))){
            inspectEndTime = (String) params.get("inspectEndTime");
        }
        if (Strings.isNotBlank((String) params.get("receivedStartTime"))){
            receivedStartTime = (String) params.get("receivedStartTime");
        }
        if (Strings.isNotBlank((String) params.get("receivedEndTime"))){
            receivedEndTime = (String) params.get("receivedEndTime");
        }

        // 构建querywrapper
        QueryWrapper<BloodSampleTestVo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Strings.isNotBlank(bloodSampleTestVo.getBloodTestId()), "bt.blood_test_id", bloodSampleTestVo.getBloodTestId())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getBloodSampleId()), "bt.blood_sample_id", bloodSampleTestVo.getBloodSampleId())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getInspector()), "bt.inspector", bloodSampleTestVo.getInspector())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getBloodId()), "bs.blood_id", bloodSampleTestVo.getBloodId())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getPlace()), "bs.place", bloodSampleTestVo.getPlace())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getRecipient()), "bs.recipient", bloodSampleTestVo.getRecipient())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getSampleStatus()), "bs.sample_status", bloodSampleTestVo.getSampleStatus())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getReason()), "bs.reason", bloodSampleTestVo.getReason())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getDepartment()), "bs.department", bloodSampleTestVo.getDepartment())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getApplicationProjects()), "bt.application_projects", bloodSampleTestVo.getApplicationProjects())
                    .eq(Strings.isNotBlank(bloodSampleTestVo.getInspectStatus()), "bt.inspect_status", bloodSampleTestVo.getInspectStatus())
                    .ge(Strings.isNotBlank(inspectStartTime), "bt.inspect_time", inspectStartTime)
                    .le(Strings.isNotBlank(inspectEndTime), "bt.inspect_time", inspectEndTime)
                    .ge(Strings.isNotBlank(receivedStartTime), "bs.received_time", receivedStartTime)
                    .le(Strings.isNotBlank(receivedEndTime), "bs.received_time", receivedEndTime);

        // IPage分页查询
        IPage<BloodSampleTestVo> page = bloodTestDao.selectSampleTestPage(
                new Query<BloodSampleTestVo>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    /**
     * 新增检测
     * @param bloodTestEntity
     * @return
     */
    @Override
    public String saveTest(BloodTestEntity bloodTestEntity) {
        // 其余的字段照常保存即可，只需对金额进行计算即可
        double price = 0; // 计算总金额
        // 初始化字典
        Map<String, Map<String, String[]>> dict = dictionaryLoader.getDict();
        //计算价格
        String paymentProject = dict.get(DictDataEnum.PAYMENT_PROJECT.code()).get(bloodTestEntity.getApplicationProjects())[1].toString();
        double unitPrice = Double.parseDouble(paymentProject.replaceAll("[^\\d.]+", ""));
        double count = Double.parseDouble(bloodTestEntity.getCount().replaceAll("[^\\d.]+",""));
        price = unitPrice * count;

        bloodTestEntity.setPrice(price);
        this.save(bloodTestEntity);
        return "检测结果保存成功！";
    }

    /**
     * 更改检测
     * @param bloodTestEntity
     * @return
     */
    @Override
    public String updateTestById(BloodTestEntity bloodTestEntity) {
        // 其他项目照常修改就行，但是一般项目金额不能改，是由申请项目对应的金额自动计算生成
        if(bloodTestEntity.getApplicationProjects() != null){
            double price = 0; // 计算总金额
            // 接下来遍历检测项目，依次累加金额
            // 字典
            Map<String, Map<String, String[]>> dict = dictionaryLoader.getDict();
            //计算价格
            String paymentProject = dict.get(DictDataEnum.PAYMENT_PROJECT.code()).get(bloodTestEntity.getApplicationProjects())[1].toString();
            double unitPrice = Double.parseDouble(paymentProject.replaceAll("[^\\d.]+", ""));
            double count = Double.parseDouble(bloodTestEntity.getCount().replaceAll("[^\\d.]+",""));
            price = unitPrice * count;

            bloodTestEntity.setPrice(price);
        }
        // 进行保存
        this.updateById(bloodTestEntity);
        return "检测信息更新成功";
    }

}